﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tedds_Tool;
using System.IO;
using Tedds_Tool.RulesBase;
using Tedds_Tool.Automatables;
using CommonInterfaces.Models;
using LEET.CommonInterfaces.Models;

namespace RulesBase.Model
{
    public class Rule : IRule
    {
        public String Name { get; private set; }
        IList<IPrecondition> Preconditions { get; set; }
        IList<IImplication> Implications { get; set; }
        public IList<IConsequence> Consequences { get; private set; }

        public static IRule Load(String ruleName, IInstructionFactory fac, IScriptFinder finder)
        {
            IRule rule = null;
            using (TextReader reader = finder.FindRule(ruleName))
            {
                IList<IPrecondition> preconditions = new List<IPrecondition>();
                IList<IImplication> implications = new List<IImplication>();
                IList<IConsequence> consequences = new List<IConsequence>();

                String [] preStrs  = reader.ReadLine().Split('|');
                foreach (String pre in preStrs)
                {
                    if(!String.IsNullOrEmpty(pre))
                        preconditions.Add(Precondition.Load(pre, fac, finder));
                }

                String[] impStrs = reader.ReadLine().Split('|');
                foreach (String imp in impStrs)
                {
                    if (!String.IsNullOrEmpty(imp))
                        implications.Add(Implication.Load(imp, fac, finder));
                }

                string con = reader.ReadLine();
                String[] consStrs = null;
                if (!string.IsNullOrEmpty(con))
                {
                    consStrs = con.Split('|');
                    foreach (String cons in consStrs)
                    {
                        if (!String.IsNullOrEmpty(cons))
                            consequences.Add(Consequence.Load(cons, finder));
                    }
                }

                rule = new Rule(ruleName, preconditions, implications, consequences);
            }
            return rule;
        }
        public static void Save(IRule rule, IScriptFinder finder)
        {
            using (TextWriter writer = finder.CreateRule(rule.Name))
            {
                writer.Write(rule.Serialize());
            }
        }

        public Rule(string name, IList<IPrecondition> preconditions, IList<IImplication> implications, IList<IConsequence> consequences)
        {
            this.Name = name;
            this.Preconditions = preconditions;
            this.Implications = implications;
            this.Consequences = consequences;
        }

        public IEnumerable<IInstruction> PreconditionInstructions
        {
            get
            {
                foreach (IPrecondition p in Preconditions)
                    foreach (IInstruction ins in p.Instructions)
                        yield return ins;
            }
        }

        public IEnumerable<IInstruction> ImplicationInstructions
        {
            get
            {
                foreach (IImplication i in Implications)
                    foreach (IInstruction ins in i.Instructions)
                        yield return ins;
            }
        }

        public IList<IConsequence> Trigger(System.Windows.Automation.AutomationElement ae)
        {
            bool preconditionsSatisfied = true;
            try
            {
                foreach (IPrecondition pre in Preconditions)
                {
                    pre.Trigger(ae);
                }
            }
            catch 
            {
                preconditionsSatisfied = false;
            }
            
            if (preconditionsSatisfied)
            {
                try
                {
                    foreach (IImplication imp in Implications)
                    {
                        imp.Trigger(ae);
                    }
                }
                catch
                {
                    return Consequences;
                }
            }

            return new List<IConsequence>();
        }

        public string Serialize()
        {
            StringBuilder buf = new StringBuilder();
            buf.Append(Join<IPrecondition>(Preconditions, " | ", delegate(IPrecondition c) { return c.Name; }));
            buf.Append("\r\n");

            buf.Append(Join<IImplication>(Implications, " | ", delegate(IImplication c) { return c.Name; }));
            buf.Append("\r\n");

            buf.Append(Join<IConsequence>(Consequences, " | ", delegate(IConsequence c){return c.Name;}));
            buf.Append("\r\n");

            return buf.ToString();
        }

        public bool ContainsPrecondition(string p)
        {
            foreach (IPrecondition pre in Preconditions)
            {
                if (pre.Name.Equals(p))
                {
                    return true;
                }
            }
            return false;
        }

        public bool ContainsImplication(string a)
        {
            foreach (IImplication imp in Implications)
            {
                if (imp.Name.Equals(a))
                {
                    return true;
                }
            }
            return false;
        }

        public bool ContainsConsequence(string c)
        {
            foreach (IConsequence cons in Consequences)
            {
                if (cons.Name.Equals(c))
                {
                    return true;
                }
            }
            return false;
        }

        private delegate String Val<T>(T a);

        private String Join<T>(IList<T> list, String join, Val<T> func){
            StringBuilder buf = new StringBuilder();
            bool insert = false;
            foreach (T t in list)
            {
                if (insert)
                {
                    buf.Append(join);
                }
                insert = true;
                buf.Append(func(t));
            }
            return buf.ToString();
        }



        
    }
}
